home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / Apple II / Essentials / Technical.Notes / IIGS / TN.IIGS.075 < prev    next >
Encoding:
Text File  |  1990-01-09  |  10.3 KB  |  202 lines  |  [TEXT/pdos]

  1. Apple II
  2. Technical Notes
  3. _____________________________________________________________________________
  4.                                                   Developer Technical Support
  5.  
  6.  
  7. Apple IIGS
  8. #75:    BeginUpdate Anomaly
  9.  
  10. Written by:    Eric Soldan                                       January 1990
  11.  
  12. This Technical Note discusses a Window Manager anomaly with the handling of 
  13. the visRgn and the updateRgn between BeginUpdate and EndUpdate calls.
  14. _____________________________________________________________________________
  15.  
  16. If an application calls BeginUpdate, it needs to be fully aware of what is 
  17. going on behind the scenes in terms of its visRgn and updateRgn.  Typically an 
  18. application has TaskMaster handle the update events.  TaskMaster calls 
  19. BeginUpdate, the application update procedure, then EndUpdate.  So any 
  20. application that uses TaskMaster to handle updates, whether or not it makes 
  21. any BeginUpdate calls directly, needs to be aware of problem described in this 
  22. Note.
  23.  
  24. BeginUpdate is responsible for intersecting the visRgn and the updateRgn and 
  25. making the intersection of these two regions the temporary visRgn.  (EndUpdate 
  26. undoes this effect.)  Following are the steps BeginUpdate takes to do this:
  27.  
  28.   1.  Localize the updateRgn.  (All grafPort regions are local, 
  29.       therefore the visRgn is local.  All window regions are global, 
  30.       therefore the updateRgn is global.  One of them has to change if 
  31.       they are to be intersected correctly.)
  32.   2.  Intersect the visRgn and localized updateRgn, then place the 
  33.       result in the updateRgn.
  34.   3.  Swap the visRgn and updateRgn handles.
  35.  
  36. The handle swapping has two effects:
  37.  
  38.       o  Makes the intersection region the current visRgn.
  39.       o  Saves the real visRgn as the updateRgn.  (Saving the real 
  40.          visRgn is necessary because everything has to be restored to 
  41.          normal by EndUpdate.)
  42.  
  43. EndUpdate restores things to normal after an update procedure is finished.  
  44. When an application calls EndUpdate, it swaps back the handles and sets the 
  45. updateRgn to empty.
  46.  
  47.  
  48. So What's the Problem?
  49.  
  50. The problem is that the updateRgn is not a very good place to save the visRgn.  
  51. Since InvalRect and InvalRgn modify the updateRgn, if either of these two 
  52. calls is made between a BeginUpdate and EndUpdate, they modify the saved 
  53. visRgn.  When the update is finished, EndUpdate restores the modified visRgn 
  54. instead of the original.
  55.  
  56. The solution to this problem seems simple enough:  don't call InvalRect or 
  57. InvalRgn between BeginUpdate and EndUpdate.  Unfortunately, there are other 
  58. calls which can call BeginUpdate, EndUpdate, InvalRect, and InvalRgn, so an 
  59. application might inadvertently call one of these routines.
  60.  
  61. If this situation isn't bad enough already, you could really mess things up by 
  62. opening another window between BeginUpdate and EndUpdate calls.  Opening a 
  63. window at this time may seem like a perfectly normal thing (i.e., to display 
  64. an alert); however, opening a window forces the recalculation of the visRgn 
  65. for any windows obscured by the new window.  If the window being updated has 
  66. its visRgn recalculated, the application obviously loses the visRgn that 
  67. BeginUpdate created.  This doesn't seem too serious since the visRgn is 
  68. restored to the entire visible part of the window when the new window is 
  69. closed; however, it does mean that the application would have to update the 
  70. entire window instead of the original updateRgn.
  71.  
  72. Unfortunately, the Window Manager also posts update events for the portion of 
  73. the window that was obscured, and it does this by changing the updateRgn.  Of 
  74. course the updateRgn for the window being updated is really the visRgn that is 
  75. being "safely" preserved until the EndUpdate call.  So, there are some really 
  76. good reasons why this can't be done.
  77.  
  78. Okay, so along with not making calls to InvalRect and InvalRgn between 
  79. BeginUpdate and EndUpdate, an application cannot open any other windows 
  80. either.  Good.
  81.  
  82. Now to make things even worse.
  83.  
  84. If you use the QuickDraw Auxiliary function CopyPixels in an update procedure, 
  85. you can get yourself in trouble.  On ROM 01 machines running System Software 
  86. 5.0 and later, the QuickDraw Auxiliary tool file has dynamic segments.  If a 
  87. disk is off-line and an application calls CopyPixels for the first time, the 
  88. system prompts the user to insert the system disk, so it can load the dynamic 
  89. segment holding CopyPixels.  Unfortunately, it does this via a regular window, 
  90. which causes all the terrible things already discussed.  So if an application 
  91. has a CopyPixels call in its update procedure, it must also be called prior to 
  92. the update procedure to make sure QuickDraw Auxiliary is loaded before 
  93. beginning the update.  If necessary, an application can use a dummy call after 
  94. starting (and after starting QuickDraw Auxiliary of course), to make sure 
  95. QuickDraw Auxiliary is loaded prior to any updates.  This dynamic segment is 
  96. never unloaded, so it is around any time the update procedure needs it.
  97.  
  98. There are some other dynamic segments in QuickDraw Auxiliary, so keep a 
  99. watchful eye on this nasty problem.
  100.  
  101.  
  102. But I Have to Do...
  103.  
  104. If you absolutely must do some of the things previously discussed, there is a 
  105. way to accomplish it.  It is not simple, but it can be done.
  106.  
  107. Assuming that BeginUpdate has been called, and an application is in its update 
  108. procedure:
  109.  
  110.   1.  Create a new region and copy the visRgn into it.  Doing this 
  111.       allows the application to restore the visRgn to just the area to 
  112.       be updated that BeginUpdate calculated.  This needs to be done for
  113.       any other windows which obscure a part the the window being 
  114.       updated.  Again, these are not windows that an application would 
  115.       open directly.  CopyPixels may open a window, since it is a 
  116.       dynamic segment and may need to get loaded from a disk that is 
  117.       off-line.
  118.   2.  Create a new region, then swap its handle with the updateRgn 
  119.       handle.  This protects the real visRgn and lets an application 
  120.       call InvalRect and InvalRgn at any time if necessary.  It also 
  121.       means the application doesn't need to worry about the system 
  122.       making these calls either.  The updateRgn is also an empty region 
  123.       after the swap, so any contributions to it constitute a valid 
  124.       update event that needs to be handled.
  125.   3.  Do the update part of the update procedure.  In this part, if the 
  126.       application has any calls to CopyPixels, or any other QuickDraw 
  127.       Auxiliary dynamic segment functions, after the call is completed, 
  128.       copy the saved visRgn back to the visRgn of the grafPort.  The 
  129.       closing of the dynamic segment alert window recalculates the 
  130.       visRgn, and copying it undoes this effect.  Do not do the same
  131.       for the updateRgn.  Leave the updateRgn alone.  We are 
  132.       accumulating an actual updateRgn, and the closing of the alert 
  133.       window for the dynamic segment may have contributed to this 
  134.       region.
  135.  
  136. There are two methods for leaving the update procedure.  Although the second 
  137. method works whether or not an application uses TaskMaster, if an application 
  138. does not use TaskMaster, then the first method is simpler.
  139.  
  140. The procedure without using TaskMaster (i.e., you made the BeginUpdate call, 
  141. and you will make the EndUpdate call) is as follows:
  142.  
  143.   A.  Dispose of the region created in Step 1.  This region was only 
  144.       needed to restore the partial visRgn that BeginUpdate calculated 
  145.       after a window was opened.
  146.   B.  Swap the updateRgn handle with the region handle created in Step 2.
  147.   C.  Make the EndUpdate call.
  148.   D.  If the region created in Step 2 is not empty, copy this region 
  149.       into the updateRgn for the window with CopyRgn.  You can't just do 
  150.       an InvalRgn with it because InvalRgn globalizes the region and the 
  151.       region is already global.  You want to copy the region since this 
  152.       generates a valid update event.  You can use CopyRgn instead of 
  153.       UnionRgn because the update region is empty.
  154.   E.  Dispose of the region created in Step 2.
  155.  
  156. With TaskMaster, things are a little messier.  Since TaskMaster makes the 
  157. EndUpdate call, you have less control over the situation.  It is important to 
  158. do the EndUpdate before generating the update event.  Posting the update event 
  159. has to happen outside the update procedure, since you have to leave the update 
  160. procedure for TaskMaster to do the EndUpdate.  So it follows that you do Steps 
  161. A and B, post an application event to handle the rest externally, and when the 
  162. application event is handled, do Steps D and E.
  163.  
  164. Some consideration was given to posting an application event via the PostEvent 
  165. call.  Unfortunately, there is a possibility that this application event will 
  166. drop out of the queue not handled.  When the queue is full, the oldest event 
  167. is dropped, and this could occur to application events, which would be very 
  168. bad in this case.  Due to this possibility, posting an application event 
  169. refers to setting a global variable that is checked before the TaskMaster call 
  170. in the main event loop.  This can be considered equivalent to posting an event 
  171. via the PostEvent call.
  172.  
  173.  
  174. So, the TaskMaster case would be as follows:
  175.  
  176.   A.  Dispose of the region created in Step 1.
  177.   B.  Swap the updateRgn handle with the region handle created in Step 2.
  178.   C.  Store the handle of the region created in Step 2 in a global 
  179.       variable named eventUpdateRgn.  Store the current window port in a 
  180.       global variable named eventWindowPort.
  181.   D.  Return to TaskMaster, which returns to the main event loop.
  182.   E.  Immediately after the TaskMaster call in the main event loop, 
  183.       check the global variable eventUpdateRgn.  If it is not NULL then:
  184.       a.  Copy the region into the updateRgn of the window 
  185.           eventWindowPort.  Using CopyRgn is the easiest way to copy the 
  186.           region.  (Copying the region posts an update event if the event 
  187.           UpdateRgn is not NULL.
  188.       b.  Dispose of the region eventUpdateRgn, then set the variable 
  189.           eventUpdateRgn to NULL, so that this "event" won't be handled 
  190.           again.
  191.  
  192. Of course, the simplest way to handle all of this is to avoid situations where 
  193. you have to take the steps described above.  If things like opening a window 
  194. (or allowing the system to open one) and InvalRect and InvalRgn can be avoided 
  195. between calls to BeginUpdate and EndUpdate, so can all of this ugliness.
  196.  
  197.  
  198. Further Reference
  199. _____________________________________________________________________________
  200.   o  Apple IIGS Toolbox Reference, Volume 2
  201.  
  202.